package zdream.pmfield.test.stage.effect;

import org.junit.Before;
import org.junit.Test;

import java.util.concurrent.atomic.AtomicInteger;

import zdream.pmfield.data.foe.BStat;
import zdream.pmfield.data.foe.Foe;
import zdream.pmfield.data.foe.MoveTemplate;
import zdream.pmfield.data.foe.Type;
import zdream.pmfield.stage.StageBuilderForTest;
import zdream.pmfield.stage.StageWrapper;
import zdream.pmfield.stage.message.FoeAddBuffMessage;
import zdream.pmfield.stage.message.FoeReceiveDamageMessage;
import zdream.pmfield.stage.message.FoeRemoveBuffMessage;
import zdream.pmfield.stage.message.TurnFinishedMessage;
import zdream.pmfield.stage.message.TurnStartMessage;
import zdream.pmfield.storage.FoeTemplateStorage;
import zdream.pmfield.test.utils.ResourceConstant;
import zdream.pmfield.test.utils.StageConstant;

import static org.junit.Assert.*;

/**
 * @author Zdream
 * @date 2023-12-08
 * @since 0.0.1
 */
public class AcidBuffCase {
	FoeTemplateStorage storage;

	@Before
	public void before() {
		storage = new FoeTemplateStorage();
		storage.load();
		storage.loadMovesInResource(ResourceConstant.RES_PATH_TEST_MOVES_JSON);
	}

	@Test
	public void testAcidBuff() {
		MoveTemplate acidMove = storage.findMoveById(10000027, 1);
		assertEquals("肯定酸蚀", acidMove.name);
		MoveTemplate normalMove = storage.findMoveById(10000015, 1);
		assertEquals("无效果", normalMove.name);

		Foe foe1 = Foe.builder(storage.findFoeById(72))
				.withLevel(30)
				.withMove(acidMove)
				.skipShuffleVStat()
				.build();
		Foe foe2 = Foe.builder(storage.findFoeById(102))
				.withLevel(30)
				.withMove(normalMove)
				.skipShuffleVStat()
				.build();
		assertTrue(foe1.bStats[BStat.SP.ordinal()] > foe2.bStats[BStat.SP.ordinal()]);

		final StageWrapper wrapper = StageBuilderForTest.builder()
				.putFoeToOneSide(foe1)
				.putFoeToAnotherSide(foe2)
				.withStorage(storage)
				.disableDistanceCheck()
				.buildWrapper();

		System.out.println("TEST 1: apply acid");
		AtomicInteger checked = new AtomicInteger(0);

		wrapper.printBeforeHandleMessage();
		wrapper.onDefaultActionRequest();
		wrapper.runUntil(TurnStartMessage.class, message -> message.foe.foe == foe1);

		wrapper.clearOnMessageHooks();
		wrapper.onActionRequestForAll(wrapper.createDefaultController().withActionChecker(action -> {
			assertEquals(acidMove, action.move.move);
			assertEquals(0, checked.getAndIncrement());
		}));
		wrapper.onMessage(FoeAddBuffMessage.class, message -> {
			assertTrue(message.buff.is(StageConstant.EFFECT_ACID));
			assertTrue(message.success);
			assertEquals(1, checked.getAndIncrement());
		});
		wrapper.onMessage(TurnFinishedMessage.class, message -> {
			assertEquals(2, checked.getAndIncrement());
		});

		wrapper.runUntil(stage0 -> checked.get() == 3);
		assertEquals(3, checked.get());
		float applyTime = wrapper.now();

		System.out.println("TEST 2: acid effect: 被酸蚀之后每回合掉护盾");
		checked.set(0);

		wrapper.clearOnMessageHooks();
		wrapper.onDefaultActionRequest();
		wrapper.onMessage(FoeReceiveDamageMessage.class, message -> {
			assertEquals(foe2, message.foe.foe);
			assertEquals(StageConstant.EFFECT_ACID, message.title);
			assertEquals(message.hpFrom, message.hpTo);
			assertTrue(message.shieldFrom > message.shieldTo);

			float time = wrapper.now();
			assertTrue(time == applyTime + checked.incrementAndGet());
		});
		wrapper.onMessage(FoeRemoveBuffMessage.class, message -> {
			throw new RuntimeException("照理说两回合内是不会自动恢复的, 肯定 foe2 的 turn 先触发");
		});

		wrapper.runUntil(TurnFinishedMessage.class);
		wrapper.runUntil(stage0 -> checked.get() == 2);
		assertEquals(2, checked.get());

		System.out.println("TEST 3: acid 效果会自动恢复");

		wrapper.clearOnMessageHooks();
		wrapper.onDefaultActionRequest();
		wrapper.runUntil(FoeRemoveBuffMessage.class, message -> {
			assertEquals(foe2, message.foe.foe);
			assertTrue(message.buff.is(StageConstant.BUFF_ACID));
			return true;
		});
	}

	@Test
	public void testSandTypeBlockAcidBuff() {
		MoveTemplate acidMove = storage.findMoveById(10000027, 1);
		assertEquals("肯定酸蚀", acidMove.name);
		MoveTemplate normalMove = storage.findMoveById(10000010, 1);
		assertEquals("肯定成功", normalMove.name);

		Foe foe1 = Foe.builder(storage.findFoeById(72))
				.withLevel(20)
				.withMove(acidMove)
				.build();
		Foe foe2 = Foe.builder(storage.findFoeById(74))
				.withLevel(20)
				.withMove(normalMove)
				.build();
		assertEquals(Type.SAND, foe2.template.types[0]);
		StageWrapper wrapper = StageBuilderForTest.builder()
				.putFoeToOneSide(foe1)
				.putFoeToAnotherSide(foe2)
				.withStorage(storage)
				.disableDistanceCheck()
				.buildWrapper();

		wrapper.printBeforeHandleMessage();

		wrapper.onDefaultActionRequest();
		wrapper.runUntil(FoeAddBuffMessage.class, message -> {
			// 酸蚀效果对砂系 (地面) 无效
			assertTrue(message.buff.is(StageConstant.BUFF_ACID));
			assertFalse(message.success);
			assertNotNull(message.rejectBy);
			assertTrue(message.rejectBy.is(StageConstant.BUFF_TYPE));
			return true;
		});
	}
}
